﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Customers;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.TaxRates;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.ObjectMapping;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class TaxRateAppService : BaseDataAppService<TaxRate, TaxRateDto, TaxRateCreateDto, TaxRateUpdateDto>, ITaxRateAppservice
    {
        private IAccountRepository _accountRepository;

        public TaxRateAppService(ITaxRateRepository repository, IDataAssociationRepository dataAssociationRepository, IGuidGenerator guidGenerator, 
            IDistributedEventBus distributedEventBus, IAccountRepository accountRepository) 
            : base(repository, dataAssociationRepository, guidGenerator, distributedEventBus)
        {
            _accountRepository = accountRepository;
        }

        public override async Task<PagedResultDto<TaxRateDto>> FindAsync(PageQuery query)
        {
            var result = await base.FindAsync(query);

            var taxRates = result.Items.ToList();

            if (taxRates.Count == 0)
                return result;

            await LoadAccountInfoAsync(taxRates);

            return result;
        }

        public override async Task<TaxRateDto> CreateAsync(TaxRateCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            await ValidateAccount(dto.InputTaxAccountId, dto.OutputTaxAccountId);

            var taxRate = new TaxRate(_guidGenerator.Create(), dto.Code, dto.Name, dto.TaxRate, dto.InputTaxAccountId, dto.OutputTaxAccountId);

            taxRate = await _repository.InsertAsync(taxRate);

            var result = ObjectMapper.Map<TaxRate, TaxRateDto>(taxRate);

            await LoadAccountInfoAsync(new List<TaxRateDto>() { result });

            //await PublishEventAsync(result, null, null);

            return result;
        }

        public override async Task<TaxRateDto> UpdateAsync(TaxRateUpdateDto dto)
        {
            var taxRate = await _repository.GetAsync(dto.Id);

            if (taxRate == null)
                throw new UserFriendlyException("税率不存在", "100000");

            var oldInputAccountId = taxRate.InputTaxAccountId;
            var oldOutputAccountId = taxRate.OutputTaxAccountId;

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(dto.InputTaxAccountId, dto.OutputTaxAccountId);

            taxRate.Change(dto.Code, dto.Name, dto.Activated);
            taxRate.ChangeRate(dto.TaxRate);
            taxRate.ChangeAccount(dto.InputTaxAccountId, dto.OutputTaxAccountId);
           

            taxRate = await _repository.UpdateAsync(taxRate);

            var result = ObjectMapper.Map<TaxRate, TaxRateDto>(taxRate);

            await LoadAccountInfoAsync(new List<TaxRateDto>() { result });

            //await PublishEventAsync(result, oldInputAccountId, oldOutputAccountId);

            return result;
        }


        #region
        private async Task LoadAccountInfoAsync(List<TaxRateDto> taxRates)
        {
            var accountIds = taxRates.Where(x => x.InputTaxAccountId != default).Select(x => x.InputTaxAccountId).ToList();

            accountIds.AddRange(taxRates.Where(x => x.OutputTaxAccountId != default).Select(x => x.OutputTaxAccountId).ToList());

            accountIds = accountIds.Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });


            foreach (var taxRate in taxRates)
            {
                taxRate.InputTaxAccountName = accounts.FirstOrDefault(x => x.Id == taxRate.InputTaxAccountId)?.FullName;
                taxRate.OutputTaxAccountName = accounts.FirstOrDefault(x => x.Id == taxRate.OutputTaxAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(Guid inputTaxAccountId, Guid outTaxAccountId)
        {
            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = new List<Guid> { inputTaxAccountId, outTaxAccountId } });

            var matchInputTaxAccount = accounts.FirstOrDefault(x => x.Id == inputTaxAccountId);

            base.ValidateAccount(matchInputTaxAccount, "进项税科目");

            var matchOutputTaxAccount = accounts.FirstOrDefault(x => x.Id == outTaxAccountId);

            base.ValidateAccount(matchOutputTaxAccount, "销项税科目");
        }

        //private async Task PublishEventAsync(TaxRateDto taxRate, Guid? oldInputTaxAccountId, Guid? oldOutputTaxAccountId, int? type = null)
        //{
        //    await PublishDataAssociationEventAsync(new List<DataAssociationEvent>()
        //    {
        //        new DataAssociationEvent()
        //        {
        //            OccupantId = taxRate.Id,
        //            OccupantType = nameof(TaxRate),
        //            OccupantTypeName="税率",
        //            OccupantCode=taxRate.Code,
        //            OccupantName=taxRate.Name,
        //            OccupiedId = taxRate.InputTaxAccountId,
        //            OldOccupiedId = oldInputTaxAccountId,
        //            OccupiedType = nameof(Account),
        //            OccupiedTypeName="科目",
        //            Type = type ?? 0
        //        },
        //        new DataAssociationEvent()
        //        {
        //            OccupantId = taxRate.Id,
        //            OccupantType = nameof(TaxRate),
        //            OccupantTypeName="税率",
        //            OccupantCode=taxRate.Code,
        //            OccupantName=taxRate.Name,
        //            OccupiedId = taxRate.OutputTaxAccountId,
        //            OldOccupiedId = oldOutputTaxAccountId,
        //            OccupiedType = nameof(Account),
        //            OccupiedTypeName="科目",
        //            Type = type ?? 0
        //        }
        //    });
        //}

        #endregion
    }
}
